package com.demo.java.concurrent;

import com.demo.java.utils.Logger;
import com.demo.java.utils.ReflectionUtil;
import com.demo.java.utils.ThreadUtils;
import lombok.Data;
import org.junit.Test;
import org.springframework.util.ReflectionUtils;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;

// -verbose:gc -XX:+PrintGCDetails
public class ThreadLocalTest {

    @Data
    private static class A {
        private String attr;
        public A(String attr) {
            this.attr = attr;
        }

        @Override
        protected void finalize() throws Throwable {
            Logger.cfo("execute gc");
        }
    }

    @Test
    public void weakreferenceTest() {
        WeakReference<A> weakreference = new WeakReference<>(new A("demo"));
        A a = weakreference.get(); // 添加强引用

        Logger.cfo("===== {}", a.getAttr());

        Logger.cfo("===== gc before");

        a = null; // 去掉强引用，让gc进行回收

        System.gc();

        Logger.cfo("===== gc end");

        a = weakreference.get();// 查看gc是否回收

        Logger.cfo("===== {}", a == null ? null : a.getAttr());


    }

    @Test
    public void threadlocalTest() throws NoSuchFieldException {

        ThreadLocal<A> tl = new ThreadLocal<>();
        tl.set(new A("demo"));

        A a = tl.get();
        Logger.cfo("==== tl value: {}", a.getAttr());

        tl = null; // 取消强引用，让gc能回收weakreference

        Logger.cfo("==== gc before");

        System.gc();

        ThreadUtils.sleep(0);

        tl = new ThreadLocal<>();

        Logger.cfo("==== tl value: {}", tl.get() == null ? null : tl.get().getAttr());

        Thread thread = Thread.currentThread();
        Class clazz = thread.getClass();
        Field threadLocalsField = clazz.getDeclaredField("threadLocals");
        threadLocalsField.setAccessible(true);
        Object field = ReflectionUtils.getField(threadLocalsField, thread);// 查看value未回收导致的内存泄漏

        Logger.cfo("==== gc end");
    }
}
